import Paragraph from '@tiptap/extension-paragraph'

function createParagraphLineNodeView() {
  return ({ node }) => {
    const dom = document.createElement('div')
    dom.className = 'render3-paragraph'
    dom.style.position = 'relative'

    const overlay = document.createElement('div')
    overlay.className = 'render3-paragraph__overlay'
    overlay.style.position = 'absolute'
    overlay.style.inset = '0'
    overlay.style.pointerEvents = 'none'
    overlay.style.display = 'block'
    overlay.style.whiteSpace = 'pre-wrap'
    dom.appendChild(overlay)

    const content = document.createElement('div')
    content.className = 'render3-paragraph__content'
    content.style.whiteSpace = 'pre-wrap'
    content.style.color = 'transparent'
    content.style.caretColor = '#1f2937'
    content.style.position = 'relative'
    content.style.display = 'block'
    dom.appendChild(content)

    let rafId = null

    const collectLineTexts = () => {
      const walker = document.createTreeWalker(
        content,
        NodeFilter.SHOW_TEXT,
      )

      const textNodes = []
      let current = walker.nextNode()
      while (current) {
        textNodes.push(current)
        current = walker.nextNode()
      }

      if (!textNodes.length) {
        const fallback = node.textContent || ''
        return fallback ? [fallback] : ['']
      }

      const lines = []
      const range = document.createRange()
      let buffer = ''
      let baseline = null
      const threshold = 1

      textNodes.forEach(textNode => {
        const value = textNode.textContent || ''
        for (let i = 0; i < value.length; i += 1) {
          const char = value[i]
          if (char === '\n') {
            lines.push(buffer)
            buffer = ''
            baseline = null
            continue
          }

          range.setStart(textNode, i)
          range.setEnd(textNode, i + 1)
          const rect = range.getBoundingClientRect()

          if (!rect || rect.height === 0) {
            buffer += char
            continue
          }

          if (baseline === null) {
            baseline = rect.top
          } else if (Math.abs(rect.top - baseline) > threshold) {
            lines.push(buffer)
            buffer = ''
            baseline = rect.top
          }

          buffer += char
        }
      })

      range.detach()

      if (buffer.length || !lines.length) {
        lines.push(buffer)
      }

      return lines
    }

    const renderLines = () => {
      overlay.innerHTML = ''
      const lines = collectLineTexts()
      lines.forEach((text, index) => {
        const lineEl = document.createElement('div')
        lineEl.className = 'render3-paragraph__line'
        lineEl.dataset.index = String(index)
        lineEl.textContent = text || '\u00a0'
        overlay.appendChild(lineEl)
      })
    }

    const scheduleRender = () => {
      if (rafId !== null) {
        cancelAnimationFrame(rafId)
      }
      rafId = window.requestAnimationFrame(() => {
        rafId = null
        renderLines()
      })
    }

    scheduleRender()

    return {
      dom,
      contentDOM: content,
      update(updatedNode) {
        if (updatedNode.type !== node.type) {
          return false
        }
        scheduleRender()
        return true
      },
      ignoreMutation: () => false,
      destroy() {
        if (rafId !== null) {
          cancelAnimationFrame(rafId)
        }
      },
    }
  }
}

const ParagraphWithLineView = Paragraph.extend({
  addNodeView() {
    return createParagraphLineNodeView()
  },
})

export default ParagraphWithLineView
